﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.IO;
using XPathEvaluator.Properties;

namespace XPathEvaluator
{
    public partial class EvaluatorForm : Form
    {
        private XmlDocument xmlDoc;
        private string xPathString;
        private string tmpXML;
        private string tmpValues;

        public EvaluatorForm()
        {
            InitializeComponent();

            this.Text = "XPath Evaluator v." + this.GetType().Assembly.GetName().Version.ToString();

            textBoxXML.WordWrap = Settings.Default.XMLWordWrap;
            textBoxResult.WordWrap = Settings.Default.XPathWordWrap;
            if (Settings.Default.XMLWordWrap)
            {
                xMLToolStripMenuItem1.Checked = true;
            }

            if (Settings.Default.XPathWordWrap)
            {
                xPathToolStripMenuItem.Checked = true;
            }

            splitContainerMain.Orientation = Settings.Default.PanelOrientation;
            if (Settings.Default.PanelOrientation == Orientation.Horizontal)
            {
                horizontalToolStripMenuItem1.Checked = true;
            }
            else
            {
                verticalToolStripMenuItem1.Checked = true;
            }

            textBoxXML.MouseWheel += new MouseEventHandler(txtBox_MouseWheel);
            textBoxResult.MouseWheel += new MouseEventHandler(txtBox_MouseWheel);

            splitContainerXPath.SplitterDistance = comboBoxXPathString.Height;
            splitContainerMain.SplitterDistance = (splitContainerMain.Orientation == Orientation.Horizontal) ? this.Height / 2 : this.Width / 2;
        }

        void txtBox_MouseWheel(object sender, MouseEventArgs e)
        {
            if (Control.ModifierKeys == Keys.Control)
            {
                if (((TextBox)sender).Font.Size + (e.Delta / 120) > 1 && ((TextBox)sender).Font.Size + (e.Delta / 120) < Single.MaxValue)
                {
                    Font newFont = new Font(((TextBox)sender).Font.FontFamily, ((TextBox)sender).Font.Size + (e.Delta / 120));
                    ((TextBox)sender).Font = newFont;
                }
            }
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openFileDialogXML.Filter = "XML|*.xml";

            DialogResult result = openFileDialogXML.ShowDialog();

            if (result == DialogResult.OK && !string.IsNullOrEmpty(openFileDialogXML.FileName))
            {
                xmlDoc = new XmlDocument();
                xmlDoc.Load(openFileDialogXML.FileName);
                textBoxXML.Text = Beautify(xmlDoc);
                
                if (textBoxXML.Size.Height < TextRenderer.MeasureText(textBoxXML.Text, textBoxXML.Font).Height)
                {
                    textBoxXML.ScrollBars = ScrollBars.Vertical;
                }

                if (textBoxXML.Size.Width < TextRenderer.MeasureText(textBoxXML.Text, textBoxXML.Font).Width)
                {
                    textBoxXML.ScrollBars = ScrollBars.Horizontal;
                }

                if (Properties.Settings.Default.RecentXMLFiles != null && !Properties.Settings.Default.RecentXMLFiles.Contains(openFileDialogXML.FileName))
                {
                    Properties.Settings.Default.RecentXMLFiles.Add(openFileDialogXML.FileName);
                    UpdateRecentXMLFilesMenu();
                }

                toolStripStatusLabel.Text = openFileDialogXML.FileName;
            }
        }

        private string Beautify(Object xml)
        {
            if (xml.GetType() == typeof(XmlDocument))
            {
                StringBuilder sb = new StringBuilder();
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;
                settings.IndentChars = "  ";
                settings.NewLineChars = "\r\n";
                settings.NewLineHandling = NewLineHandling.Replace;

                using (XmlWriter writer = XmlWriter.Create(sb, settings))
                {
                    ((XmlDocument)xml).Save(writer);
                }

                return sb.ToString();
            }
            else if (xml.GetType() == typeof(String))
            {
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.ConformanceLevel = ConformanceLevel.Fragment;

                StringBuilder myXMLString = new StringBuilder();

                using (XmlReader reader = XmlReader.Create(new StringReader((String)xml), settings))
                {
                    XmlWriterSettings wsettings = new XmlWriterSettings();
                    wsettings.Indent = true;
                    wsettings.ConformanceLevel = ConformanceLevel.Fragment;

                    using (XmlWriter writer = XmlWriter.Create(myXMLString, wsettings))
                    {
                        while (reader.Read())
                        {
                            switch (reader.NodeType)
                            {
                                case XmlNodeType.Element:
                                    writer.WriteStartElement(reader.Name);
                                    break;
                                case XmlNodeType.Text:
                                    writer.WriteString(reader.Value);
                                    break;
                                case XmlNodeType.XmlDeclaration:
                                case XmlNodeType.ProcessingInstruction:
                                    writer.WriteProcessingInstruction(reader.Name, reader.Value);
                                    break;
                                case XmlNodeType.Comment:
                                    writer.WriteComment(reader.Value);
                                    break;
                                case XmlNodeType.EndElement:
                                    writer.WriteFullEndElement();
                                    break;
                            }
                        }
                    }
                }

                return myXMLString.ToString();
            }
            else return null;
        }

        private void comboBoxXPathString_SelectionChangeCommitted(object sender, EventArgs e)
        {
            textBoxResult.Text = null;

            if (!string.IsNullOrEmpty(comboBoxXPathString.Text))
            {
                xPathString = comboBoxXPathString.Text;

                try
                {
                    XmlNodeList nodeList = xmlDoc.SelectNodes(xPathString);

                    tmpXML = String.Empty;
                    //tmpValues = String.Empty;

                    foreach (XmlNode x in nodeList)
                    {
                        tmpXML += x.InnerXml;
                        //tmpValues += x.InnerText + Environment.NewLine;
                    }

                    if (!string.IsNullOrEmpty(tmpXML))
                    {
                        textBoxResult.Text = Beautify(tmpXML);
                        if (textBoxResult.Size.Height < TextRenderer.MeasureText(textBoxResult.Text, textBoxResult.Font).Height)
                        {
                            textBoxResult.ScrollBars = ScrollBars.Vertical;
                        }
                    }
                    else
                    {
                        textBoxResult.Text = "No result or XPath string invalid.";
                    }
                }
                catch (Exception ex)
                {
                    textBoxResult.Text = ex.Message;
                }
            }
        }

        private void UpdateRecentXMLFilesMenu()
        {
            if (Properties.Settings.Default.RecentXMLFiles != null)
            {
                openToolStripMenuItem.DropDown.Items.Clear();

                foreach (string s in Properties.Settings.Default.RecentXMLFiles)
                {
                    openToolStripMenuItem.DropDown.Items.Add(s);
                }
            }
        }

        private void horizontalToolStripMenuItem_Click(object sender, EventArgs e)
        {
            horizontalToolStripMenuItem1.Checked = true;
            verticalToolStripMenuItem1.Checked = false;
            splitContainerMain.Orientation = Orientation.Horizontal;
            splitContainerMain.SplitterDistance = (splitContainerMain.Orientation == Orientation.Horizontal) ? this.Height / 2 : this.Width / 2;
        }

        private void verticalToolStripMenuItem_Click(object sender, EventArgs e)
        {
            horizontalToolStripMenuItem1.Checked = false;
            verticalToolStripMenuItem1.Checked = true;
            splitContainerMain.Orientation = Orientation.Vertical;
            splitContainerMain.SplitterDistance = (splitContainerMain.Orientation == Orientation.Horizontal) ? this.Height / 2 : this.Width / 2;
        }

        private void xMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (xMLToolStripMenuItem1.Checked)
            {
                xMLToolStripMenuItem1.Checked = false;
                textBoxXML.WordWrap = false;
            }
            else
            {
                xMLToolStripMenuItem1.Checked = true;
                textBoxXML.WordWrap = true;
            }
        }

        void CheckIfScrollbarsNeeded(object sender, EventArgs e)
        {
            if (((TextBox)sender).Size.Height < TextRenderer.MeasureText(((TextBox)sender).Text, ((TextBox)sender).Font).Height)
            {
                ((TextBox)sender).ScrollBars = ScrollBars.Vertical;
            }

            if (((TextBox)sender).Size.Width < TextRenderer.MeasureText(((TextBox)sender).Text, ((TextBox)sender).Font).Width)
            {
                ((TextBox)sender).ScrollBars = ScrollBars.Horizontal;
            }
        }

        private void xPathResultToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (xPathToolStripMenuItem.Checked)
            {
                xPathToolStripMenuItem.Checked = false;
                textBoxResult.WordWrap = false;
            }
            else
            {
                xPathToolStripMenuItem.Checked = true;
                textBoxResult.WordWrap = true;
            }
        }

        private void EvaluatorForm_Resize(object sender, EventArgs e)
        {
            splitContainerXPath.SplitterDistance = comboBoxXPathString.Height;
            splitContainerMain.SplitterDistance = (splitContainerMain.Orientation == Orientation.Horizontal) ? this.Height / 2 : this.Width / 2;
        }

        private void comboBoxXPathString_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)
            {
                comboBoxXPathString_SelectionChangeCommitted(sender, e);
            }
        }

        private void EvaluatorForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            Properties.Settings.Default.Save();
        }
    }
}
